<template>
  <div>
    <div
      class="het-search-panel flex justify-between items-center mb-[16px]"
      v-if="config.search.config.length != 0"
    >
      <HETForm1
        ref="searchFormEl"
        v-model="searchForm"
        :inline="true"
        :formConfig="config.search.config"
      >
      </HETForm1>
      <div class="flex items-center">
        <span
          class="flex items-center mr-[10px] cursor-pointer"
          @click="clearSearch"
          ><el-icon class="mr-[5px]"><Brush /></el-icon>清空条件</span
        >
        <el-button type="primary" icon="Search" @click="getTableData()"
          >搜索</el-button
        >
      </div>
    </div>
    <div class="table-container het-panel">
      <div class="tree-side" v-if="treeSide.show">
        <h1>{{ treeSide.title }}</h1>
        <el-tree
          ref="tableTreeSide"
          :data="treeData"
          :props="treeProps"
          node-key="id"
          :expand-on-click-node="false"
          accordion
          :current-node-key="0"
          highlight-current
          :default-expand-all="true"
        >
          <template #default="{ node }">
            <div class="add-tree-node" v-if="node.data.type == 'input'">
              <el-input
                ref="treeInputRef"
                v-model="node.data.label"
                @blur="addNewNode(node)"
                @keyup.enter.native="treeInputRef.blur()"
              ></el-input>
            </div>
            <div
              class="custom-tree-node"
              v-else
              @mouseenter="node.data.showIcon = true"
              @mouseleave="node.data.showIcon = false"
            >
              <span
                class="node-label"
                :title="node.label"
                @click="handleClickNode(node)"
                >{{ node.label }}</span
              >
              <span class="node-icon" v-show="node.data.showIcon">
                <el-icon
                  
                  v-if="treeSide.allowAdd && node.level <= 3"
                  @click="handleAddNode(node)"
                  ><Plus
                /></el-icon>
                <el-icon
                  v-if="node.data.id != 0 && treeSide.allowDel"
                  @click="deleteNode(node)"
                  class="ml-[5px]"
                  ><Delete
                /></el-icon>
              </span>
            </div>
          </template>
        </el-tree>
      </div>
      <div
        class="table-main"
        v-loading="load"
        :style="{ width: treeSide.show ? 'calc(100% - 192px)' : '100%' }"
      >
        <!-- <Transition name="autoHeight">
        <div
          class="table-search"
          v-if="config.search.config.length != 0"
          v-show="searchFormDown"
        >
          <HETForm1
            ref="searchFormEl"
            v-model="searchForm"
            :inline="true"
            :formConfig="config.search.config"
          >
          </HETForm1>
          <div>
            <span style="font-size: 14px; margin-right: 10px"
              >模糊查询：<el-switch
                v-model="operator"
                active-value="like"
                inactive-value="="
                size="small"
              ></el-switch
            ></span>
            <el-button type="primary" icon="Search" @click="getTableData()"
              >查询</el-button
            >
            <el-button icon="RefreshRight" @click="clearSearch">清空</el-button>
          </div>
        </div>
      </Transition> -->
        <div class="control-btn" v-if="config.controlBtns?.length > 0">
          <div class="btn-group">
            <template v-for="(item, index) in config.controlBtns" :key="index">
              <el-button
                v-if="item.type == 'delete'"
                :icon="markRaw(item.icon)"
                type="danger"
                :disabled="
                  item.disabled
                    ? item.disabled(selectData)
                    : selectData.length == 0
                    ? true
                    : false
                "
                @click="delSelectRows()"
              >
                {{ item.name }}
              </el-button>
              <template v-else-if="item.render">
                <component :is="item.render(selectData)" />
              </template>
              <el-button
                v-else
                :icon="markRaw(item.icon)"
                :type="item.type"
                :disabled="item.disabled ? item.disabled(selectData) : false"
                @click="item.handleClick()"
              >
                {{ item.name }}
              </el-button>
            </template>
          </div>
          <!-- <div class="table-search" v-if="config.search">
          <el-input
            v-model="searchKeys"
            style="width: 200px; height: 32px; margin-right: 12px"
            v-bind="config.search"
            :prefix-icon="Search"
          />
          <el-button type="primary" :icon="Search" @click="getTableData()"
            >查询</el-button
          >
          <el-button :icon="RefreshRight" @click="searchKeys = '';getTableData()"
            >清空</el-button
          >
        </div> -->
          <!-- <div class="control-other">
          <el-button
            v-if="config.search.config.length != 0"
            circle
            icon="Search"
            size="small"
            title="展开/收起筛选"
            @click="searchFormDown = !searchFormDown"
          />
        </div> -->
        </div>

        <el-table
          :data="tableData"
          ref="refTable"
          max-height="730"
          @select="select"
          :show-header="true"
          @select-all="select"
          row-key="id"
          show-overflow-tooltip
        >
          <template v-for="(item, index) in config.columns">
            <el-table-column
              v-if="item.type != 'slot'"
              :key="index"
              :type="item.type"
              :label="item.label"
              :prop="item.prop"
              :width="item.type == 'selection' ? 34 : item.width"
              :selectable="item.selectable"
              show-overflow-tooltip
            >
              <template v-if="item.custom?.type == 'text'" #default="scope">
                {{ item.custom.handleFunc(scope.row) }}
              </template>
              <template
                v-else-if="item.custom?.type == 'switch'"
                #default="scope"
              >
                <el-switch
                  v-model="scope.row[item.prop]"
                  v-bind="item.custom.bind"
                  :disabled="
                    item.custom.disabledFn
                      ? item.custom.disabledFn(scope.row)
                      : false
                  "
                  inline-prompt
                  @change="item.custom.handleFunc(scope.row)"
                />
              </template>
              <template
                v-else-if="item.custom?.type == 'button'"
                #default="scope"
              >
                <template v-for="(btn, index) in item.custom.operatBtns">
                  <template v-if="btn.type == 'delete'">
                    <el-popconfirm
                      :title="btn.tip || '确定删除该记录?'"
                      cancel-button-text="取消"
                      confirm-button-text="确认"
                      @confirm="
                        btn.delConfirm
                          ? btn.delConfirm(scope.row)
                          : delCurrentRow([{ id: scope.row.id }])
                      "
                    >
                      <template #reference>
                        <el-button
                          :key="index"
                          size="small"
                          type="primary"
                          :text="true"
                          :disabled="
                            btn.disabledFn ? btn.disabledFn(scope.row) : false
                          "
                          >{{ btn.name }}
                        </el-button>
                      </template>
                    </el-popconfirm>
                  </template>
                  <template v-else>
                    <el-button
                      :key="index"
                      v-bind="btn.setting ? btn.setting(scope.row) : {}"
                      type="primary"
                      size="small"
                      :text="true"
                      :disabled="
                        btn.disabledFn ? btn.disabledFn(scope.row) : false
                      "
                      @click="btn.handleClick(scope.row)"
                      >{{ btn.name }}</el-button
                    >
                  </template>
                </template>
              </template>
              <template v-else-if="item.render" #default="scope">
                <component :is="item.render(scope.row)" />
              </template>
              <template v-else-if="item.formatter" #default="scope">
                {{ item.formatter(scope.row) }}
              </template>
              <template v-else-if="item.type == 'expand'" #default="scope">
                {{ item.formatter(scope.row) }}
              </template>
            </el-table-column>
            <slot v-else :name="item.slotName ? item.slotName : ''"> </slot>
          </template>

          <!-- <template slot="empty"></template> -->
        </el-table>
        <div class="paginationWrap">
          <el-pagination
            style="justify-content: flex-end"
            :hide-on-single-page="false"
            :page-size="pageSize"
            :page-sizes="[10, 20, 50]"
            :page-count="maxPage ? maxPage : 1"
            :pager-count="7"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            background
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          ></el-pagination>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {
  ref,
  reactive,
  computed,
  onMounted,
  markRaw,
  nextTick,
  toRef,
} from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { commonApi } from "~/utils/axios/common.js";
import { mAxios } from "../utils/axios/axios";

const props = defineProps({
  // 表格配置
  config: {
    type: Object,
    default: {
      // 模块名
      module: null,
      // 搜索
      search: {
        form: {},
        config: [],
      },
      sorts: ["id"],
      // 默认排序方式
      sorted: "asc",
      // 列
      columns: [],
      // 表格顶部操作按钮
      controlBtns: [],
    },
  },
  treeSide: {
    type: Object,
    default: {
      show: false,
      title: "",
      module: null,
      // props: null,
      filter: {
        field: "",
        operator: "=",
        value: null,
      },
      allowAdd: false,
      allowDel: false,
    },
  },
  // 请求额外参数
  query: {
    type: Object,
    default: null,
  },
});
const maxPage = computed(() => {
  return total.value > 10000
    ? Math.ceil(10000 / pageSize.value)
    : Math.ceil(total.value / pageSize.value);
});

// 显示or隐藏表单查询
const searchFormDown = ref(true);
// 查询条件
const searchForm = toRef(props.config.search?.form);
const treeFilter = toRef(props.treeSide.filter);
// 查询时的匹配模式（模糊查询like，精准查询=）
const operator = ref("=");
// 构造查询条件参数filters
const filters = computed(() => {
  let list = [];
  if (treeFilter.value.value != null) {
    list.push(treeFilter.value);
  }
  if (props.query && Object.keys(props.query).length != 0) {
    Object.keys(props.query).forEach((key) => {
      list.push({
        field: key,
        operator: "=",
        value: props.query[key],
      });
    });
  }
  for (var k in searchForm.value) {
    if (searchForm.value[k]) {
      list.push({
        field: k,
        operator: operator.value,
        value: searchForm.value[k],
      });
    }
  }

  return list;
});
// 查询的字段
const columns = computed(() => {
  let cols = [];
  // props.config.columns.forEach((item) => {
  //   if (item.prop) {
  //     cols.push({
  //       field: item.prop,
  //     });
  //   }
  // });
  return cols;
});
// 表格相关
const tableData = ref([]);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
const load = ref(false);
const selectData = ref([]);

// 树形组件相关
const tableTreeSide = ref();
const treeData = ref([]);
const treeProps = {
  children: "child",
  label: "name",
  value: "id",
};
const defaultExpandNodes = [0];

onMounted(() => {
  getTreeSideData();
  getTableData();
});

// 多选
const select = (selection) => {
  selectData.value = selection;
};
const handleSizeChange = (val) => {
  pageSize.value = val;
  getTableData();
};
// 翻页
const handleCurrentChange = (page) => {
  currentPage.value = page;
  getTableData();
};
// 清空查询条件
const clearSearch = () => {
  for (var k in searchForm.value) {
    searchForm.value[k] = "";
  }
  getTableData();
};
const getTableData = () => {
  load.value = true;
  if (props.config.selectApi) {
    const params = {
      page: currentPage.value,
      size: pageSize.value,
      ...props.config.search.form,
    };
    return props.config
      .selectApi(params)
      .then((res) => {
        load.value = false;
        tableData.value = res.data.data.rows;
        total.value = res.data.data.total;
        selectData.value = [];
      })
      .catch(() => {
        load.value = false;
      });
  }
  if (props.config.module) {
    const params = {
      page: currentPage.value - 1,
      size: pageSize.value,
      filters: filters.value,
      sorts: props.config.sorts, //["id"],
      columns: columns.value,
      sorted: props.config.sorted,
    };
    commonApi
      .generalQuery(props.config.module, params)
      .then((res) => {
        load.value = false;
        tableData.value = res.data.data;
        total.value = res.data.total;
        selectData.value = [];
      })
      .catch((err) => {
        load.value = false;
      });
  }
};
// 表格批量删除
const delSelectRows = () => {
  if (selectData.value.length == 0) {
    ElMessage.error("请选择需要删除的选项!");
    return;
  }
  ElMessageBox.confirm("确定要删除所选项？", "批量删除", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    center: true,
    closeOnClickModal: false,
    type: "warning",
  }).then(() => {
    let params = selectData.value.map((item) => {
      return { id: item.id };
    });
    delCurrentRow(params);
  });
};
// 单个删除
const delCurrentRow = (params) => {
  if (props.config.deleteApi) {
    return props.config.deleteApi(params).then((res) => {
      res.data.succeed
        ? ElMessage.success("删除成功")
        : ElMessage.error("删除失败");
      getTableData();
    });
  }
  if (props.config.module) {
    commonApi.generalDelete(props.config.module, params).then((res) => {
      res.data.succeed
        ? ElMessage.success("删除成功")
        : ElMessage.error("删除失败");
      getTableData();
    });
  }
};

const getTreeSideData = () => {
  if (!props.treeSide.show) return;
  const params = {
    filters: [],
    sorts: ["id"],
    columns: [],
    sorted: "asc",
  };
  commonApi.generalQuery(props.treeSide.module, params).then((res) => {
    const groups = [...res.data.data];
    groups.forEach((item) => {
      item.child = groups.filter((g) => g.pid === item.id);
    });
    treeData.value = [{ pid: -1, id: 0, name: "全部", child: [] }].concat(
      groups.filter((item) => item.pid === 0)
    );

    nextTick(() => {
      const nodes = tableTreeSide.value.el$.querySelectorAll(".el-tree-node");
      nodes.forEach((nodeElement) => {
        const key = nodeElement.getAttribute("data-key");
        const node = tableTreeSide.value.getNode(key);
        const indentBase = 10; // 基础缩进量
        const indent = (node.level-1) * indentBase;
        nodeElement.style.setProperty("--node-indent", `${indent}px`);
      });
    });
  });
};

const treeInputRef = ref();
const handleAddNode = (node) => {
  node.expand();
  setTimeout(() => {
    node.data.child.unshift({
      pid: node.data.id,
      label: "",
      child: [],
      type: "input",
    });
    nextTick(() => {
      treeInputRef.value.focus();
    });
  }, 300);
};
const addNewNode = (node) => {
  let params = {
    name: node.data.label,
    pid: node.data.pid,
  };
  if (params.name != "") {
    commonApi
      .generalAdd(props.treeSide.module, params)
      .then((res) => {
        res.data.succeed
          ? ElMessage.success("添加成功")
          : ElMessage.error("添加失败");
        getTreeSideData();
        treeFilter.value.value = null;
        getTableData();
      })
      .catch((err) => {
        tableTreeSide.value.remove(node);
      });
  } else {
    tableTreeSide.value.remove(node);
  }
};
const deleteNode = (node) => {
  ElMessageBox.confirm("确定要删除分组" + node.data.name + "？", "删除分组", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    center: true,
    closeOnClickModal: false,
    type: "warning",
  }).then(() => {
    if (props.treeSide.deleteApi) {
      return props.treeSide.deleteApi([{ id: node.data.id }]).then((res) => {
        res.data.succeed
          ? ElMessage.success("删除成功")
          : ElMessage.error(res.data.errorMsg);
        getTreeSideData();
        treeFilter.value.value = null;
        getTableData();
      });
    }
    if (props.treeSide.module) {
      commonApi
        .generalDelete(props.treeSide.module, [{ id: node.data.id }])
        .then((res) => {
          res.data.succeed
            ? ElMessage.success("删除成功")
            : ElMessage.error("删除失败");
          getTreeSideData();
          treeFilter.value.value = null;
          getTableData();
        });
    }
  });
};
const handleClickNode = (node) => {
  if (node.data.id == 0) {
    treeFilter.value.value = null;
  } else {
    treeFilter.value.value = node.data.id;
  }
  getTableData();
};

defineExpose({ getTableData, selectData });
</script>

<style lang="scss" scoped>
.table-container {
  display: flex;
  justify-content: space-between;
  .tree-side {
    width: 168px;
    h1 {
      font-size: 16px;
      font-weight: 700;
      border-bottom: 1px solid #eee;
      padding: 15px 10px;
      margin-bottom: 10px;
    }
    .custom-tree-node {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .node-label {
        display: flex;
        align-items: center;
        width: 85px;
        height: 100%;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
      }
      .node-icon {
        position: relative;
        display: flex;
        align-items: center;
        cursor: pointer;
        :deep(.el-icon):hover {
          color: #8901b4;
        }
        .dropdown-menu {
          position: absolute;
          top: 15px;
          left: -78px;
          width: 95px;
          background-color: #fff;
          box-shadow: 0px 0px 5px 0px #d4d4d4;
          border-radius: 3px;
          padding: 10px;
          z-index: 999;
          li {
            display: flex;
            align-items: center;
            color: #333333;
            font-weight: normal;
            padding: 5px 5px;
            border-radius: 3px;
            &:hover {
              background: #f5f7fa;
            }
          }
        }
      }
    }
    .add-tree-node {
      :deep(.el-input) {
        height: 22px;
      }
    }
  }
  .table-main {
    width: 85%;
  }
}
.table-search {
  display: flex;
  // justify-content: space-between;
  border-bottom: 1px solid #ddd;
  // padding: 10px 0 15px 0;
  // transition: all 0.2s ease-out;
}
.control-btn {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.operation {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
.paginationWrap {
  padding-top: 15px;
  :deep(.el-pagination__sizes .el-select) {
    width: 95px;
  }
  :deep(.el-pagination > *.is-last) {
    margin-left: 5px;
  }
  :deep(.el-pager .number) {
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    background: #ffffff;
    &:hover {
      color: #9800c8;
      border-color: #9800c8;
    }
  }
  :deep(.el-pager .is-active) {
    font-weight: 500;
    &:hover {
      color: #fff;
    }
  }
}
.autoHeight-enter-active,
.autoHeight-leave-active {
  max-height: 200px;
  transition: all 0.3s;
  overflow: hidden;
}
.autoHeight-enter-from,
.autoHeight-leave-to {
  max-height: 0;
}
.el-button + .is-text {
  margin: 0 !important;
}
:deep(.el-tree) {
  background: #fff;
}
:deep(.el-tree-node__content) {
  height: 36px;
  border-radius: 3px;
}
:deep(
    .el-tree--highlight-current
      .el-tree-node.is-current
      > .el-tree-node__content
  ) {
  background-color: #f5f7fa;
  font-weight: 600;
  font-size: 14px;
  color: #333333;
}
:deep(.el-tree-node__content) {
  padding-left: var(--node-indent, 0px) !important;
}
</style>
